﻿// Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

// added namespaces
using System.Data.Objects;
using MyTravelPostModel;
using System.Collections;
using System.Data;
using System.Data.Objects.DataClasses;

namespace MyTravelPostService
{
    public class MyTravelPostService : IMyTravelPostService
    {
        // see IMyTravelPostService for details.
        public List<Blog> GetAllTravelBlogs()
        {
            try
            {
                // the creation of the travelEntities opens the connection 
                // and sets up all the metadata information automatically for you.
                using (MyTravelPostEntities travelEntities = new MyTravelPostEntities())
                {
                    // set the blogs merge option to no tracking since this is a
                    // service that doesn't need to have change tracking.
                    travelEntities.Blogs.MergeOption = MergeOption.NoTracking;

                    // need to always span in the Person because logically I want to always
                    // have the person with the blog - see how this is serialized in
                    // MyTravelModelExtension.cs
                    var blogs = from b in travelEntities.Blogs.Include("Person")
                                where b.BlogPosts.Count > 0
                                select b;
                    return blogs.ToList();
                }
            }
            catch (Exception ex)
            {
                // NOTE: You should do your own exception handling here
                // problems may be connection, metadata, or there problems.
                throw ex;
            }
        }

        // see IMyTravelPostService for details.
        public Blog GetBlog(int blogID)
        {
            try
            {
                // the creation of the travel MyTravelPostEntities opens the connection 
                // and sets up all the metadata information automatically for you.
                using (MyTravelPostEntities travelEntities = new MyTravelPostEntities())
                {
                    // set the blogs merge option to no tracking since this is a
                    // service that doesn't need to have change tracking.
                    travelEntities.Blogs.MergeOption = MergeOption.NoTracking;

                    // query for a specific blog posting
                    // return the first one.
                    // I include Person in the span parameter as I always want the person
                    // to be serialized with the blog.
                    // Note: Since we use the EntityKey that is put on the EntityReference
                    // we can either do a tracking query or use span.
                    Blog blog = (from b in travelEntities.Blogs.Include("Person")
                                 where b.BlogID == blogID
                                 select b).First();
                    return blog;
                }
            }
            catch (Exception ex)
            {
                // NOTE: You should do your own exception handling here
                // problems may be connection, metadata, or there problems.
                throw ex;
            }
        }

        // see IMyTravelPostService for details.
        public BlogPost GetLatestBlogPosting(Blog requestedBlog)
        {
            try
            {
                // the creation of the travel MyTravelPostEntities opens the connection 
                // and sets up all the metadata information automatically for you.
                using (MyTravelPostEntities travelEntities = new MyTravelPostEntities())
                {
                    // set the blogs merge option to no tracking since this is a
                    // service that doesn't need to have change tracking.
                    travelEntities.BlogPosts.MergeOption = MergeOption.NoTracking;

                    // get the latest blog post, with the comments and the people
                    // I'm querying for all the blog posts that are related to this blog.
                    // I want to include the comments and the people that wrote the comments.
                    // I also want only the most recent posting.
                    // Note: Since we use the EntityKey that is put on the EntityReference
                    // we can either do a tracking query or use span.
                    BlogPost post = (from bp in travelEntities.BlogPosts
                                                                .Include("Comments.Person")
                                                                .Include("Blog")
                                     where bp.Blog.BlogID == requestedBlog.BlogID
                                     orderby bp.BlogDate descending
                                     select bp).First();
                    return post;
                } 
            }
            catch (Exception ex)
            {
                // NOTE: You should do your own exception handling here
                // problems may be connection, metadata, or there problems.
                throw ex;
            }
        }

        // see IMyTravelPostService for details.
        public List<Person> GetPeople()
        {
            try
            {
                // the creation of the travel MyTravelPostEntities opens the connection 
                // and sets up all the metadata information automatically for you.
                using (MyTravelPostEntities travelEntities = new MyTravelPostEntities())
                {
                    // set the blogs merge option to no tracking since this is a
                    // service that doesn't need to have change tracking.
                    travelEntities.People.MergeOption = MergeOption.NoTracking;
                    return travelEntities.People.ToList();
                }
            }
            catch (Exception ex)
            {
                // NOTE: You should do your own exception handling here
                // problems may be connection, metadata, or there problems.
                throw ex;
            }
        }

        // see IMyTravelPostService for details.
        public Comment AddComment(Comment newComment)
        {
            try
            {
                // the creation of the travel MyTravelPostEntities opens the connection 
                // and sets up all the metadata information automatically for you.
                using (MyTravelPostEntities travelEntities = new MyTravelPostEntities())
                {                
                    // add the comment, since the comment carries the dependent ends as 
                    // EntityReferences, this is all that is need to update the database.
                    travelEntities.AddToComments(newComment);

                    // once you have the reference, the properties are changed
                    // tracked so modifications are update during SaveChanges
                    try
                    {
                        travelEntities.SaveChanges();
                    }
                    catch (OptimisticConcurrencyException opt)
                    {
                        // catching this exception allows you to 
                        // refresh MyTravelPostEntities with either store/client wins
                        // project the MyTravelPostEntities into this failed MyTravelPostEntities.
                        var failedEntities = from e3 in opt.StateEntries
                                             select new { e3.Entity };

                        // Note: in future you should be able to just pass the opt.StateEntities in to refresh.
                        travelEntities.Refresh(RefreshMode.ClientWins, failedEntities.ToList());
                        travelEntities.SaveChanges();
                    } 
                }
            }
            catch (Exception ex)
            {
                // NOTE: You should do your own exception handling here
                // problems may be connection, metadata, or there problems.
                throw ex;
            }

            // return the comment, this will be updated now.
            return newComment;
        }

        // see IMyTravelPostService for details.
        public void DeleteComment(Comment deleteComment)
        {
            try
            {
                // the creation of the travel MyTravelPostEntities opens the connection 
                // and sets up all the metadata information automatically for you.
                using (MyTravelPostEntities travelEntities = new MyTravelPostEntities())
                {
                    // attach the comment and delete.
                    travelEntities.Attach(deleteComment);

                    // call delete on the object
                    travelEntities.DeleteObject(deleteComment);

                    try
                    {
                        travelEntities.SaveChanges();
                    }
                    catch (OptimisticConcurrencyException opt)
                    {
                        // catching this exception allows you to 
                        // refresh travelEntities with either store/client wins
                        // project the travelEntities into this failed travelEntities.
                        var failedEntities = from e3 in opt.StateEntries
                                             select new { e3.Entity };

                        // Note: in future you should be able to just pass the opt.StateEntities in to refresh.
                        travelEntities.Refresh(RefreshMode.ClientWins, failedEntities.ToList());
                        travelEntities.SaveChanges();
                    }
                }
            }
            catch (Exception ex)
            {
                // NOTE: You should do your own exception handling here
                // problems may be connection, metadata, or there problems.
                throw ex;
            }
        }

        // see IMyTravelPostService for details.
        public List<Comment> UpdateComments(List<Comment> orginalComments, List<Comment> updateComments)
        {
            try
            {
                // the creation of the travel travelEntities opens the connection 
                // and sets up all the metadata information automatically for you.
                using (MyTravelPostEntities travelEntities = new MyTravelPostEntities())
                {
                    // loop through the orginal comments and attach them to the context.
                    foreach (Comment orginalComment in orginalComments)
                    {
                        travelEntities.Attach(orginalComment);
                    }  

                    // now that the original are inserted, take the update comments
                    // and call ApplyPropertyChanges. This will look up the entity
                    // being tracked and apply changes to the properties.
                    foreach (Comment updatedComment in updateComments)
                    {
                        travelEntities.ApplyPropertyChanges("Comments", updatedComment);
                    }
                    
                    // once you have the reference, the properties are changed
                    // tracked so modifications are update during SaveChanges
                    try
                    {
                        travelEntities.SaveChanges();
                    }
                    catch (OptimisticConcurrencyException opt)
                    {
                        // catching this exception allows you to 
                        // refresh travelEntities with either store/client wins
                        // project the travelEntities into this failed travelEntities.
                        var failedEntities = from e3 in opt.StateEntries
                                             select new { e3.Entity };

                        // Note: in future you should be able to just pass the opt.StateEntities in to refresh.
                        travelEntities.Refresh(RefreshMode.ClientWins, failedEntities.ToList());
                        travelEntities.SaveChanges();
                    } 
                }
            }
            catch (Exception ex)
            {
                // NOTE: You should do your own exception handling here
                // problems may be connection, metadata, or there problems.
                throw ex;
            }

            // return the orginal comments, these objects will be updated now.
            return orginalComments;
        }

        // see IMyTravelPostService for details.
        public void ChangeBlogowner(Blog blog, EntityKey newBlogOwnerKey)
        {
          try
            {
                // the creation of the travel MyTravelPostEntities opens the connection 
                // and sets up all the metadata information automatically for you.
                using (MyTravelPostEntities travelEntities = new MyTravelPostEntities())
                {
                    // attach the blog,
                    travelEntities.Attach(blog);

                    // by having the EntityKey on the PersonReference
                    // you can change the relationship to a new blog owner
                    // via the entity key. The new EntityKey must exists in the database
                    blog.PersonReference.EntityKey = newBlogOwnerKey;

                    try
                    {
                        travelEntities.SaveChanges();
                    }
                    catch (OptimisticConcurrencyException opt)
                    {
                        // catching this exception allows you to 
                        // refresh travelEntities with either store/client wins
                        // project the travelEntities into this failed travelEntities.
                        var failedEntities = from e3 in opt.StateEntries
                                             select new { e3.Entity };

                        // Note: in future you should be able to just pass the opt.StateEntities in to refresh.
                        travelEntities.Refresh(RefreshMode.ClientWins, failedEntities.ToList());
                        travelEntities.SaveChanges();
                    }
                }
            }
            catch (Exception ex)
            {
              // NOTE: You should do your own exception handling here
              // problems may be connection, metadata, or there problems.
              throw ex;
            }
        }
    }
}
